﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Collections.Specialized;
using System.Xml.Serialization;
using System.IO;
using System.Diagnostics;

namespace ShootSearch.FileSystem
{
    public class FileObjectText : NameValueCollection, IXmlSerializable, IFileObject
    {
        public const string URL = "Url";
        public const string DATETIME = "DateTime";
        public const string DELETED = "Deleted";
        public const string ENCODING = "Encoding";
        public const string CONTENTTYPE = "ContentType";
        public const string ID = "text/fileobjecttext";
        protected FileObject fileObject = new FileObject() { ContentType = "text/fileobjecttext" };

        public FileObjectText()
        {
        }

        public FileObjectText(string url)
        {
            this.fileObject.Url = url;
        }

        public FileObjectText(string url, DateTime dt)
        {
            this.fileObject.Url = url;
            this.DateTime = dt;
        }


        public FileObjectText(FileObject fileObject)
        {
            this.fileObject = fileObject;
            this.LoadAttributes(fileObject.Content);
        }

        #region IFileObject Members

        public bool Deleted
        {
            get { return fileObject.Deleted; }
            set { fileObject.Deleted = value; }
        }
        public DateTime DateTime 
        {
            get { return fileObject.DateTime; }
            set { fileObject.DateTime = value; }
        }
        public Encoding Encoding
        {
            get { return fileObject.Encoding; }
            set { fileObject.Encoding = value; }
        }
        public string Url
        {
            get { return fileObject.Url; }
            set { fileObject.Url = value; }
        }
        public string ContentType
        {
            get { return fileObject.ContentType; }
            set {}
        }

        public byte[] Content
        {
            get { return AttributesBytes(); }
            set { LoadAttributes(value); }
        }

        public void Read(Stream stream)
        {
            fileObject.Read(stream);
            LoadAttributes(fileObject.Content);
        }

        public void Write(Stream stream)
        {

            fileObject.Content = AttributesBytes();
            fileObject.Write(stream);
        }

        public byte[] ToBytes()
        {
            fileObject.Content = AttributesBytes();
            return fileObject.ToBytes();
        }

        public void FromBytes(byte[] bytes)
        {
            fileObject.FromBytes(bytes);
            LoadAttributes(fileObject.Content);
        }

        #endregion

        #region IXmlSerializable Members

        public System.Xml.Schema.XmlSchema GetSchema()
        {
            return new System.Xml.Schema.XmlSchema();
        }

        public void ReadXml(System.Xml.XmlReader reader)
        {
            reader.ReadToFollowing("Deleted");
            Deleted = reader.ReadElementContentAsBoolean();

            reader.ReadToFollowing("DateTime");
            DateTime = reader.ReadElementContentAsDateTime();

            reader.ReadToFollowing("Encoding");
            string encodeName = reader.ReadString();
            try
            {
                Encoding = Encoding.GetEncoding(encodeName.Trim());
            }
            catch (Exception ex)
            {
                Trace.WriteLine(ex);
            }

            reader.ReadToFollowing("Url");
            Url = reader.ReadString();

            reader.ReadToFollowing("ContentType");
            ContentType = reader.ReadString();

            while (reader.ReadToFollowing("Attribute"))
            {
                reader.ReadToFollowing("Name");
                string name = reader.ReadString();
                reader.ReadToFollowing("Value");
                string value = reader.ReadString();
                this.Add(name, value);
            }

        }

        public void WriteXml(System.Xml.XmlWriter writer)
        {
            writer.WriteStartElement("Deleted");
            writer.WriteValue(Deleted);
            writer.WriteEndElement();

            writer.WriteStartElement("DateTime");
            writer.WriteValue(DateTime);
            writer.WriteEndElement();

            writer.WriteStartElement("Encoding");
            writer.WriteValue(Encoding.HeaderName);
            writer.WriteEndElement();

            writer.WriteStartElement("Url");
            writer.WriteValue(Url);
            writer.WriteEndElement();

            writer.WriteStartElement("ContentType");
            writer.WriteValue(ContentType);
            writer.WriteEndElement();

            writer.WriteStartElement("Attributes");
            for (int i = 0; i < this.Count; i++)
            {
                writer.WriteStartElement("Attribute");
                writer.WriteStartElement("Name");
                writer.WriteValue(this.GetKey(i));
                writer.WriteEndElement();
                writer.WriteStartElement("Value");
                writer.WriteValue(this[i]);
                writer.WriteEndElement();
                writer.WriteEndElement();
            }

            writer.WriteEndElement();
        }

        #endregion

        #region Other Public Methods
        public byte[] AttributesBytes()
        {
            MemoryStream ms = new MemoryStream();
            BinaryWriter bw = new BinaryWriter(ms);
            for (int i = 0; i < this.Count; i++)
            {
                string name = this.GetKey(i);
                string value = this[i];

                byte[] buff = fileObject.Encoding.GetBytes(name);
                bw.Write(buff.Length);
                bw.Write(buff);

                buff = fileObject.Encoding.GetBytes(value);
                bw.Write(buff.Length);
                bw.Write(buff);
            }

            ms.Seek(0, SeekOrigin.Begin);
            byte[] bytes = new byte[(int)ms.Length];
            ms.Read(bytes, 0, bytes.Length);

            bw.Close();
            ms.Close();
            return bytes;
        }

        public void LoadAttributes(byte[] bytes)
        {
            BinaryReader br = new BinaryReader(new MemoryStream(bytes));
            while (br.BaseStream.Position < br.BaseStream.Length - 1)
            {
                int length = br.ReadInt32();
                string name = fileObject.Encoding.GetString(br.ReadBytes(length));
                length = br.ReadInt32();
                string value = fileObject.Encoding.GetString(br.ReadBytes(length));
                this.Add(name, value);
            }
            br.Close();
        }

        public FileObject GetFileObject()
        {
            fileObject.Content = this.AttributesBytes();
            return fileObject;
        } 
        #endregion
    }
}
